# -*- coding: utf-8 -*-
# @Time    : 2024/7/5 09:49
# @Author  : yujiahao
# @File    : 04_fastapi_query_parameters.py
# @description:查询参数
from typing import Union

from fastapi import FastAPI

app = FastAPI()

fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


# todo 1、 声明的参数不是路径参数时，路径操作函数会把该参数自动解释为查询参数。
@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    '''
    查询字符串是键值对的集合，这些键值对位于 URL 的 ? 之后，以 & 分隔。

        例如，以下 URL 中：http://127.0.0.1:8000/items/?skip=0&limit=10

        查询参数为：

            skip：值为 0
            limit：值为 10
            这些值都是 URL 的组成部分，因此，它们的类型本应是字符串。

        但声明 Python 类型（上例中为 int）之后，这些值就会转换为声明的类型，并进行类型校验。
        所有应用于路径参数的流程也适用于查询参数：

        - （显而易见的）编辑器支持
        - 数据解析
        - 数据校验
        - API 文档
    【默认值】

    查询参数不是路径的固定内容，它是可选的，还支持默认值。

    用 skip=0 和 limit=10 设定默认值。

    访问 URL：http://127.0.0.1:8000/items/
    与访问以下地址相同：http://127.0.0.1:8000/items/?skip=0&limit=10
    但如果访问：http://127.0.0.18000/items/?skip=20
    查询参数的值就是：skip=20：在 URL 中设定的值；limit=10：使用默认值

    '''

    # 切片
    return fake_items_db[skip: skip + limit]


# todo 2、可选参数


@app.get("/items/{item_id}")
async def choince_read_item(item_id: str, q: int | None = None):
    '''
    - 就是说，将默认的值的类型设置为None或者其他类型，可以选择，这里3.8+是用Unit(str:None)这种语法联合的，3.10+之后用 |
    - 这里的q是可选的，默认为None
    - 路径参数 是通过路径字符串中的占位符 {} 定义的，必须出现在 URL 路径中。
    - 查询参数 是通过 URL 中的查询字符串定义的，使用 ? 和 & 连接，出现在路径参数之后。
    '''
    if q:
        return {"item_id": item_id, "q": q}
    return {"item_id": item_id}


# todo 3、 查询参数类型转换

@app.get("/items/{item_ids}")
async def read_item_type(item_ids: str, q: Union[str, None] = None, short: bool = False):
    '''
    访问：http://127.0.0.1:8000/items/foo?short=1
    或 http://127.0.0.1:8000/items/foo?short=True
    或 http://127.0.0.1:8000/items/foo?short=true
    或 http://127.0.0.1:8000/items/foo?short=on
    或 http://127.0.0.1:8000/items/foo?short=yes
    或其它任意大小写形式（大写、首字母大写等），函数接收的 short 参数都是布尔值 True。值为 False 时也一样。

    '''
    item = {"item_id": item_ids}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item


# todo 4、多个路径和查询参数
@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
        user_id: int, item_id: str, q: Union[str, None] = None, short: bool = False
):
    item = {"item_id": item_id, "owner_id": user_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item


# 5、必选查询参数
@app.get("/item/{item_id}")
async def read_user_item_must(item_id: str, needy: str):
    '''
    - 如果要把查询参数设置为必选，也就是说必须在调用的时候传递进来，那么就不要生命默认值，这样在调用的时候这个参数就必须有值，
    - needy 是必选参数，因此要在 URL 中设置值：http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
    - 把一些参数定义为必选，为另一些参数设置默认值，再把其它参数定义为可选，这些操作都是可以的：

        @app.get("/items/{item_id}")
        async def read_user_item(
            item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None
        ):
            item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
            return item

    - 有 3 个查询参数：
        - needy，必选的 str 类型参数
        - skip，默认值为 0 的 int 类型参数
        - limit，可选的 int 类型参数
    '''
    item = {"item_id": item_id, "needy": needy}
    return item
